import redis
import pickle
import uuid
import time


class TCPManager:
    _instance = None
    _redis_conn = None

    def __init__(self, channle='tcp_server'):
        self.channle = channle
        self._redis_conn = redis.Redis(
            host='127.0.0.1', port='6379', db=1, max_connections=100)

    def gen_callback_id(self):
        '''生成唯一标示'''
        return str(uuid.uuid4())

    def offer(self, d_id, msg, handle_type, is_callback=True, time_out=10):
        '''
            向tcp服务器广播操作tcp连接的请求
        '''

        callback_id = self.gen_callback_id()

        pub = self._redis_conn.pubsub()
        pub.subscribe(self.channle)

        self._redis_conn.publish(self.channle, pickle.dumps({
            'type': 'offer',
            'd_id': d_id,
            'msg': msg,
            'handle_type': handle_type,
            '_call_back_id': callback_id
        }))

        start = time.time()
        while is_callback:
            if (time.time() - start) >= time_out:
                pub.close()
                return None
            wait_time = time_out - (time.time() - start)
            res = pub.parse_response(block=False, timeout=wait_time)
            if not res:
                continue
            msg_type, channel, msg = res
            msg_type, channel = msg_type.decode(
                'utf-8'), channel.decode('utf-8')
            if msg_type != 'message' or channel != self.channle:
                continue
            try:
                msg = pickle.loads(msg)
                if msg['type'] != 'answer':
                    continue
            except Exception as e:
                print(e)
                continue

            if msg['_call_back_id'] == callback_id:
                pub.close()
                return msg

    def answer(self, call_back_id, msg):
        '''向发送者广播返回结果'''
        self._redis_conn.publish(self.channle, pickle.dumps({
            'type': 'answer',
            '_call_back_id': call_back_id,
            'msg': msg
        }))

    @classmethod
    def get_instance(cls):
        '''单例模式'''

        if cls._instance:
            return cls._instance
        return cls()
